home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
prime2.exe
/
PRIME2.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-06
|
11KB
|
362 lines
/******************************************************************************
* prime2.c
*
* (C) 1992 L.I.Kirby CIS: 70734,126
*
* 6th September 1992
*
* A couple of algorithms to list and count primes up to reasonably large
* totals (say 2^32).
*
* Both algorithms make use of rolling totals to generate multiples of the base
* primes, i.e. the primes < sqrt(targetprime)
*****************************************************************************/
#include <stdio.h>
#include <ctype.h>
#define ROLLSIZE (3405) /* Big enough to hold all of the base primes */
#define SIEVESIZE (16000) /* Must be > largest base prime/2 */
#define SENTINEL (~0L) /* Largest possible value for heap endstop */
typedef unsigned long LARGE_T; /* Variables up to targetprime */
typedef unsigned int SMALL_T; /* Variables less than sqrt(targetprime) */
typedef int bool;
#define FALSE (0)
#define TRUE (!0)
/* Function prototypes */
int main(int, char **);
static long prime_heap(LARGE_T, bool);
static void downheap(void);
static long prime_sieve(LARGE_T, bool);
/* Statics */
static LARGE_T S_roll[ROLLSIZE+1];
static SMALL_T S_increm[ROLLSIZE+1];
/********************************** main() **********************************
* Decode command options and call prime routine.
*/
int main(argc, argv)
int argc;
char **argv;
{
int i;
char *sptr;
enum { AL_HEAP, AL_SIEVE } algorithm;
LARGE_T targetprime;
bool printflag;
long primecount;
algorithm = AL_SIEVE;
targetprime = 0L;
printflag = FALSE;
for (i = 1; i < argc; i++) {
sptr = argv[i];
if (*sptr == '-' || *sptr == '/') {
while (*++sptr) switch (toupper(*sptr)) {
case 'P':
printflag = TRUE;
break;
case 'N':
printflag = FALSE;
break;
case 'S':
algorithm = AL_SIEVE;
break;
case 'H':
algorithm = AL_HEAP;
break;
default:
break;
}
} else
(void) sscanf(sptr, "%lu", &targetprime);
}
if (!targetprime) {
puts("\nUsage: prime2 [-options] target");
puts("target: Search up to but excluding target");
puts("Options: P - print primes");
puts(" N - do not print primes (default)");
puts(" H - use heap method");
puts(" S - use sieve method (default)");
return(1);
}
switch (algorithm) {
case AL_HEAP:
primecount = prime_heap(targetprime, printflag);
break;
case AL_SIEVE:
primecount = prime_sieve(targetprime, printflag);
break;
}
printf("\n\nNumber of primes found is %ld\n", primecount);
return(0);
}
/******************************* prime_heap() *******************************
* This method maintains a running multiple (the roll) for each base prime.
* These are maintained in a heap structure so that the smallest roll value
* i.e. next non-prime is easily determined. Even numbers are skipped.
*
* Although slower than the sieve method, this method uses less memory and
* still avoids the dreaded divides.
*/
static long prime_heap(targetprime, printflag)
LARGE_T targetprime; /* Maximum search number */
bool printflag; /* TRUE is primes should be printed */
{
register LARGE_T num; /* The current number being tested for primeness */
long nextnonprime; /* The next smallest number which has a factor */
long primecount; /* The number of primes found so far */
bool gtsqrt; /* Set to TRUE once we go beyond sqrt*targetprime) */
SMALL_T rollhwm; /* High watermark for roll arrays */
printf("\nPrime Heap prime search up to %lu\n", targetprime);
/* Initialise array with sentinels for heap */
for (num = 1; num <= ROLLSIZE; num++)
S_roll[num] = SENTINEL;
/* Deal with the special case of 2 */
primecount = 0;
if (targetprime > 2) {
primecount++;
if (printflag)
printf("\n 2");
}
/* The main routine */
rollhwm = 1; /* Starting at 1 simplifies the heap routines */
num = 3;
nextnonprime = 9;
gtsqrt = FALSE;
for (;;) { /* Here all odd numbers between num and nextnonprime are prime */
do {
if (num >= targetprime) /* FINISHED! */
return(primecount);
primecount++; /* Found a prime, count and print it */
if (printflag)
printf(" %7lu", num);
/* If num < sqrt(targetprime) then add to end of heap */
if (!gtsqrt) {
if (num * num >= targetprime)
gtsqrt = TRUE;
else {
if (rollhwm >= ROLLSIZE) {
printf("\nROLLSIZE too small. Maximum target is %lu\n",
num * num);
exit(1);
}
S_roll[rollhwm] = num * num;/* Smallest we need look at -
guaranteed to be greater than
any current heap entry */
S_increm[rollhwm] = 2 * num;/* Skip over even values */
rollhwm++;
}
}
num += 2;
} while (num < nextnonprime);
/* We've reached nextnonprime. Search for next prime */
do {
do {
S_roll[1] += S_increm[1]; /* Roll to next odd multiple */
downheap(); /* Repair heap */
} while (num == S_roll[1]);
} while ((num += 2) == S_roll[1]);
nextnonprime = S_roll[1];
}
}
/******************************** downheap() ********************************
* Maintains a heap such that:
* S_roll[n] <= S_roll[2*n] and S_roll[n] < S_roll[2*n+1]
* i.e. S_roll[1] is the smallest element in the heap.
*
* This routine repairs a heap where only the first element is out of order.
* It expectc unused array elements to contain SENTINEL
*/
static void downheap()
{
register int i, j;
SMALL_T increm;
LARGE_T roll;
i = 1;
increm = S_increm[1];
roll = S_roll[1];
while ((j = 2 * i) < ROLLSIZE) {
if (S_roll[j] > S_roll[j+1])
j++;
if (roll <= S_roll[j])
break;
S_roll[i] = S_roll[j];
S_increm[i] = S_increm[j];
i = j;
}
S_increm[i] = increm;
S_roll[i] = roll;
}
/****************************** prime_sieve() *******************************
* This method maintains a running multiple (the roll) for each base prime
* similar to prime_heap(). However this method uses the multiples to help
* generate a sieve in sections small enough to fit in memory.
*
* S_sieve[] must be at least sqrt(targetprime) in size but larger values
* will generally be more efficient. Even numbers are ignored.
*/
static long prime_sieve(targetprime, printflag)
LARGE_T targetprime; /* Maximum search number */
bool printflag; /* TRUE is primes should be printed */
{
register SMALL_T rp, sp;
LARGE_T roll, prime;
SMALL_T sectlen;
LARGE_T sectstart, sectend;
SMALL_T rollhwm; /* High watermark for roll arrays */
long primecount; /* The number of primes found so far */
bool gtsqrt; /* Set to TRUE once we go beyond sqrt*targetprime) */
static char S_sieve[SIEVESIZE];
printf("\nSieve prime search up to %lu\n", targetprime);
if (targetprime > (LARGE_T) 4 * SIEVESIZE * SIEVESIZE) {
printf("\nSIEVESIZE too small. Maximum target is about %lu\n",